#include "w25q.h"

uint8_t flash_operate_buf[SECTOR_SIZE];
uint32_t oper_addr;
//variable_packs_list_t variable_packs_list;
flash_controller_t flash_controller;
uint8_t user_write_buf[16];

//Save_variable_packs_list_t save_Variable_list;

static uint8_t SPI_TransmitReceive(uint8_t data) {
    uint8_t rx_data;
    HAL_SPI_TransmitReceive(&HSPI, &data, &rx_data, 1, 100);
    return rx_data;
}

static void SPI_SEND(uint8_t data){
    HAL_SPI_Transmit(&HSPI, &data, sizeof(data), 0xFF);
}

static void w25q_send_addr(uint32_t addr){
    SPI_SEND((uint8_t)(addr >> 16));
    SPI_SEND((uint8_t)(addr >> 8));
    SPI_SEND((uint8_t)(addr));
} 

static void enable_write(){
    CS_L;
    SPI_SEND(ALLOW_WRITE);
    CS_H;
}

static uint32_t flash_read_id(void){
    uint8_t temp[3];
    CS_L;
    SPI_TransmitReceive(READ_ID);
    temp[2] = SPI_TransmitReceive(0xFF);
    temp[1] = SPI_TransmitReceive(0xFF);
    temp[0] = SPI_TransmitReceive(0xFF);
    CS_H;
    return (temp[2] << 16) | (temp[1] << 8) | temp[0];
}

void flash_controller_init(void){
		
		clear_operate_buf();
    flash_controller.flash_exsit_if = 0;
    flash_controller.flash_state = SEARCH_FLASH;
    flash_controller.now_ms_cnt = 0;
    flash_controller.wait_ms = 0;
    flash_controller.read_len = 0;
    flash_controller.start_read = 0;
    flash_controller.read_addr = 0;
    flash_controller.clear_all = 0;
    flash_controller.to_clear_sector_id = 0;
    flash_controller.clear_sector = 0;
    flash_controller.read_sector = 0;
    flash_controller.to_read_sector_id = 0;
}

uint32_t watch_id;

void flash_controller_auto(void){
    flash_controller.now_ms_cnt ++;
    if(flash_controller.flash_state == SEARCH_FLASH){
				oper_addr = GET_RAM_ADDR(flash_operate_buf);
        if(flash_controller.now_ms_cnt >= flash_controller.wait_ms){
            uint32_t id = flash_read_id();
					watch_id = id;
            if((id & 0x0000FFFF) == FLASH_ID){
                flash_controller.flash_exsit_if = 1;
                flash_controller.flash_state = FLASH_WAIT;
                flash_controller.next_flash_state = FLASH_IDLE;
                flash_controller.wait_ms = 1;
                flash_controller.now_ms_cnt = 0;
                enable_write();
            }
            else{
                flash_controller.wait_ms = 500;
                flash_controller.now_ms_cnt = 0;
                flash_controller.next_flash_state = SEARCH_FLASH;
            }
        }
    }
    else if (flash_controller.flash_state == FLASH_WAIT)
    {
        if(flash_controller.now_ms_cnt >= flash_controller.wait_ms){
            flash_controller.now_ms_cnt = 0;
            flash_controller.flash_state = flash_controller.next_flash_state;
        }
    }
    else if(flash_controller.flash_state == FLASH_BUSY){
        flash_controller.now_ms_cnt = 0;
        if(!check_busy()){
            flash_controller.flash_state = flash_controller.next_flash_state;
        }
    }
    else if(flash_controller.flash_state == FLASH_IDLE){
        flash_controller.now_ms_cnt = 0;
        if(flash_controller.start_read){
            read_flash(flash_controller.read_addr, flash_controller.read_len);
            flash_controller.start_read = 0;
        }
        else if (flash_controller.clear_all){
            clear_flash();
            flash_controller.clear_all = 0;
        }
        else if (flash_controller.start_write){
            rewrite_flash(&user_write_buf[0],flash_controller.write_addr, flash_controller.write_len);
            flash_controller.start_write = 0;
        }
        else if (flash_controller.clear_sector){
            clear_sector(flash_controller.to_clear_sector_id);
            flash_controller.clear_sector = 0;
        }
        else if(flash_controller.read_sector){
            read_sector(&flash_operate_buf[0], flash_controller.to_read_sector_id);
            flash_controller.read_sector = 0;
        }
		check_busy();
    }
}



void clear_flash(void){
    enable_write();
    CS_L;
    flash_controller.flash_state = FLASH_BUSY;
    SPI_SEND(CLEAR_ALL);
    CS_H;
		wait_busy();
}

void clear_sector(uint16_t sector_id){
    enable_write();
    CS_L;
    flash_controller.flash_state = FLASH_BUSY;
    SPI_SEND(CLEAR_SECTOR);
    if(sector_id >= SECTOR_NUM){
        sector_id = SECTOR_NUM - 1;
    }
    w25q_send_addr(sector_id*SECTOR_SIZE);
    CS_H;
		wait_busy();
}

void read_flash(uint32_t addr_start, uint16_t read_len){
	enable_write();
    CS_L;
    flash_controller.flash_state = FLASH_BUSY;
    SPI_SEND(READ_DATA);
    w25q_send_addr(addr_start);
    if(read_len > MAX_READ_BUF){
        read_len = MAX_READ_BUF - 1;
    }
    for(int i=0;i<read_len;i++){
        flash_controller.read_buf[i] = SPI_TransmitReceive(0xFF);
    }
	wait_busy();
}


void write_flash(uint32_t addr_start, uint16_t write_len){
		while(flash_controller.flash_state == FLASH_BUSY){
			DELAY(1);
		}
		enable_write();
    CS_L;
    flash_controller.flash_state = FLASH_BUSY;
    SPI_SEND(WRITE_PAGE);
    w25q_send_addr(addr_start);
    if(write_len > MAX_WRITE_BUF){
        write_len = MAX_WRITE_BUF - 1;
    }
    for(int i=0;i<write_len;i++){
        SPI_TransmitReceive(flash_controller.write_buf[i]);
    }
    CS_H;
		wait_busy();
}

void clear_operate_buf(){
    memset(&flash_operate_buf[0],0xFF,SECTOR_SIZE);
}

void read_sector(uint8_t* read_buf, uint16_t sector_id){
    clear_operate_buf();
    uint32_t addr_start = sector_id * SECTOR_SIZE;
    for(int i=0;i<SECTOR_SIZE / MAX_READ_BUF; i++){
        read_flash(addr_start + i * MAX_READ_BUF, MAX_READ_BUF);
        memcpy(&read_buf[i * MAX_READ_BUF], &flash_controller.read_buf[0], sizeof(flash_controller.read_buf));
    }
}

void write_sector(uint8_t* write_buf, uint16_t sector_id){
    uint32_t addr_start = sector_id * SECTOR_SIZE;
    for(int i=0;i<SECTOR_SIZE / MAX_READ_BUF; i++){
        memcpy(&flash_controller.write_buf[0], &write_buf[i*MAX_WRITE_BUF], sizeof(flash_controller.write_buf));
        write_flash(addr_start + i * MAX_READ_BUF, MAX_READ_BUF);
    }
}

// void check_if_can_write_flash_info(){
//     if(log_controller.this_ms_update_flash_info == 0){

//     }
// }

uint8_t rewrite_flash(uint8_t* write_buf,uint32_t addr_start, uint32_t write_len){
    uint16_t sector_id_start = addr_start / SECTOR_SIZE;
    uint16_t sector_id_end = (addr_start + write_len) / SECTOR_SIZE;
    uint16_t bytes_left_first_sector = addr_start - sector_id_start * SECTOR_SIZE;
    uint16_t bytes_left_end_sector = addr_start + write_len - sector_id_end * SECTOR_SIZE;
    uint16_t operate_size = 0;
    for(int i = sector_id_start; i <= sector_id_end; i++){
        read_sector(&flash_operate_buf[0],i);
        if(i == sector_id_start){
						memcpy(&flash_operate_buf[bytes_left_first_sector], &write_buf[operate_size], write_len > SECTOR_SIZE - bytes_left_first_sector?SECTOR_SIZE - bytes_left_first_sector:write_len);
            operate_size += write_len > SECTOR_SIZE - bytes_left_first_sector?SECTOR_SIZE - bytes_left_first_sector:write_len;
        }
        else{
            if(sector_id_start < sector_id_end){
                if(i != sector_id_end){
                    memcpy(&flash_operate_buf[0], &write_buf[operate_size], SECTOR_SIZE);
                    operate_size += SECTOR_SIZE;
                }
                else{
                    memcpy(&flash_operate_buf[0], &write_buf[operate_size], bytes_left_end_sector);
                    operate_size += bytes_left_end_sector;
                }
            }
        }
		clear_sector(i);
    write_sector(&flash_operate_buf[0],i);
    }
    return write_len == operate_size;
}

void clean_data(uint32_t addr_start, uint32_t data_len){
    fill_data(0xFF, addr_start, data_len);
}

void fill_data(uint8_t data, uint32_t addr_start, uint32_t data_len){
    uint16_t cut_pieces = data_len / 256 + 1;
    uint16_t now_operate_size = 0;
    uint32_t total_operate_size = 0;
    for(int i=0;i<cut_pieces;i++){
        if(i == cut_pieces - 1){
            now_operate_size = data_len - i*256;
        }else{
            now_operate_size = 256;
        }
        uint8_t* temp_ff = (uint8_t*)pvPortMalloc(now_operate_size);
        memset(temp_ff, data, now_operate_size);
        rewrite_flash(temp_ff, total_operate_size + addr_start, now_operate_size);
        total_operate_size += now_operate_size;
        vPortFree(temp_ff);
    }
}

void get_flash_data(uint8_t* read_buf, uint32_t addr,uint16_t read_len){
    uint16_t operate_size = 0;
    uint8_t cut_pieces = read_len / MAX_READ_BUF + 1;
    for(int i=0; i< cut_pieces; i++){
        uint16_t read_leng = 0;
        if(i == cut_pieces - 1){
            read_leng = read_len - (cut_pieces - 1) * MAX_READ_BUF;
        }
        else{
            read_leng = MAX_READ_BUF;
        }
        read_flash(addr + i*MAX_READ_BUF, read_leng);
        memcpy(&read_buf[i*MAX_READ_BUF], &flash_controller.read_buf[0], read_leng);
        operate_size += read_leng;
    }
}

uint8_t check_busy(void){
    CS_L;
    SPI_SEND(CHECK_BUSY);
    if(SPI_TransmitReceive(0xFF) & 0x01){
        flash_controller.flash_state = FLASH_BUSY;
        flash_controller.next_flash_state = FLASH_IDLE;
        CS_H;
        return 1;
    }
    else{
        CS_H;
        return 0;
    }
}

void wait_busy(void){
	while(check_busy()){DELAY(1);};
}

//void REGISTER_SAVE_VARIABLES(uint32_t var_ram_addr, Variable_TYPE type){
//    Save_Variable_pack_t var_pack = {.data_ram_addr = var_ram_addr, .type = type};
//    if(save_Variable_list.now_num < MAX_INIT_LOG_NUM){
//        save_Variable_list.variable_packs[save_Variable_list.now_num++] = var_pack;
//        save_Variable_list.data_len += SIZEOF(type);
//    }
//}

//void add_variable_pack(Variable_pack_t var_pack){
//    if(variable_packs_list.now_num < MAX_Variable_NUM){
//        variable_packs_list.variable_packs[variable_packs_list.now_num++] = var_pack;
//        variable_packs_list.data_len += SIZEOF(var_pack.type);
//    }
//}

//void update_variable_pack_list(){
//    variable_packs_list.data_len = 0;
//    for(int i=0;i<variable_packs_list.now_num;i++){
//        uint8_t operate_raw_length = SIZEOF(variable_packs_list.variable_packs[i].type);
//        memcpy(&variable_packs_list.variable_packs[i].data.raw[0],(void*)variable_packs_list.variable_packs[i].data_ram_addr, operate_raw_length);
//        variable_packs_list.data_len += SIZEOF(variable_packs_list.variable_packs[i].type);
//    }
//}


// user function

// user function
